#ifndef __COMMINTERFACE_H
#define __COMMINTERFACE_H

#include "bsp_config.h"

#ifdef __cplusplus
extern "C" {
#endif

#include <stdio.h>
#include "usart.h"
#include "wl_ringbuff.h"

typedef enum {
#ifdef UART1_USING
    COMM_UART1,
#endif

#ifdef UART2_USING
    COMM_UART2,
#endif

#ifdef UART3_USING
    COMM_UART3,
#endif

#ifdef UART4_USING
    COMM_UART4,
#endif

#ifdef UART5_USING
    COMM_UART5,
#endif

#ifdef UART6_USING
    COMM_UART6,
#endif
    COMM_UART_MAX,

    COMM_SPI1 = COMM_UART_MAX,
    COMM_MAX
}COMM_TYPE_ENUM;


/* if hardware changed, please match code here */
#define DEBUG_COMM_TYPE                             COMM_UART1          /* DEBUG  AT */
#define AT_COMM_TYPE                                COMM_UART1          
// #define ACU_COMM_TYPE                               COMM_UART2          /* ACU  PDA SMARTHOST */
// #define VCU1_COMM_TYPE                              COMM_UART3          /* vice mcu */
#if defined(WL_PROJECT_COKE)
#define VCU2_COMM_TYPE                              COMM_UART5
#elif defined(WL_PROJECT_COOPER) || defined(WL_PROJECT_APATO)
// #define VCU2_COMM_TYPE                              COMM_UART6
#ifdef TCU_MODULE
#define TCU_COMM_TYPE                               COMM_UART5
#endif
#endif 

// #define VCU1_COMM_TYPE                              COMM_UART4
// #define EXTERNAL_COMM_TYPE                          COMM_UART5          /* PLAYLOAD */
// #define VCU2_COMM_TYPE                              COMM_UART4

#define SI4463_COMM_TYPE 					        COMM_SPI1
/* if hardware changed, please match code here */

typedef struct {
    uint8_t userId;
    COMM_TYPE_ENUM commType;
} commUserIdTableTypedef;


#define MAX_ITEM_SIZE                       264
#define BUF_LOG_ITEM_SIZE                   255
#define BUF_AT_ITEM_SIZE                    80

/* one comm must define :
   1. the rx item size, must greater than the max rx data length by this comm
   2. rx item size, make sure that the rx data will not be lost
   3. the tx item size, must greater than the max tx data length by this comm
   4. tx item size, make sure that the tx data will not be lost
   5. tx ring div, will dive the tx items. will be called by different task.
*/

/* debug */
#ifdef UART1_USING
#define BUF_UART1_RX_ITEM_SIZE              BUF_AT_ITEM_SIZE
#define BUF_UART1_RX_RING_ITEM_NUM          2
#define BUF_UART1_RX_DMA_SIZE               (2*BUF_UART1_RX_ITEM_SIZE)

#define BUF_UART1_TX_ITEM_SIZE              BUF_LOG_ITEM_SIZE
#define BUF_UART1_TX_RING_ITEM_NUM          30
#define BUF_UART1_TX_RING_DIV               2
#else
#define BUF_UART1_RX_ITEM_SIZE              0
#define BUF_UART1_RX_RING_ITEM_NUM          0
#define BUF_UART1_RX_DMA_SIZE               0
#define BUF_UART1_TX_ITEM_SIZE              0
#define BUF_UART1_TX_RING_ITEM_NUM          0
#endif

/* acu */
#ifdef UART2_USING
#define BUF_UART2_RX_ITEM_SIZE              148
#define BUF_UART2_RX_RING_ITEM_NUM          8
#define BUF_UART2_RX_DMA_SIZE               (2*BUF_UART2_RX_ITEM_SIZE)

#define BUF_UART2_TX_ITEM_SIZE              264
#define BUF_UART2_TX_RING_ITEM_NUM          70
#define BUF_UART2_TX_RING_DIV               5
#else
#define BUF_UART2_RX_ITEM_SIZE              0
#define BUF_UART2_RX_RING_ITEM_NUM          0
#define BUF_UART2_RX_DMA_SIZE               0
#define BUF_UART2_TX_ITEM_SIZE              0
#define BUF_UART2_TX_RING_ITEM_NUM          0
#endif

/* VCU */
#ifdef UART3_USING
#define BUF_UART3_RX_ITEM_SIZE              264
#define BUF_UART3_RX_RING_ITEM_NUM          8
#define BUF_UART3_RX_DMA_SIZE               (2*BUF_UART3_RX_ITEM_SIZE)

#define BUF_UART3_TX_ITEM_SIZE              148
#define BUF_UART3_TX_RING_ITEM_NUM          8
#define BUF_UART3_TX_RING_DIV               1
#else
#define BUF_UART3_RX_ITEM_SIZE              0
#define BUF_UART3_RX_RING_ITEM_NUM          0
#define BUF_UART3_RX_DMA_SIZE               0
#define BUF_UART3_TX_ITEM_SIZE              0
#define BUF_UART3_TX_RING_ITEM_NUM          0
#endif

/* VCU */
#ifdef UART4_USING
#define BUF_UART4_RX_ITEM_SIZE              264
#define BUF_UART4_RX_RING_ITEM_NUM          8
#define BUF_UART4_RX_DMA_SIZE               (2*BUF_UART4_RX_ITEM_SIZE)

#define BUF_UART4_TX_ITEM_SIZE              148
#define BUF_UART4_TX_RING_ITEM_NUM          8
#define BUF_UART4_TX_RING_DIV               1
#else
#define BUF_UART4_RX_ITEM_SIZE              0
#define BUF_UART4_RX_RING_ITEM_NUM          0
#define BUF_UART4_RX_DMA_SIZE               0
#define BUF_UART4_TX_ITEM_SIZE              0
#define BUF_UART4_TX_RING_ITEM_NUM          0
#endif

/* playload */
#ifdef UART5_USING
#define BUF_UART5_RX_ITEM_SIZE              264
#define BUF_UART5_RX_RING_ITEM_NUM          8
#define BUF_UART5_RX_DMA_SIZE               (2*BUF_UART5_RX_ITEM_SIZE)

#define BUF_UART5_TX_ITEM_SIZE              148
#define BUF_UART5_TX_RING_ITEM_NUM          8
#define BUF_UART5_TX_RING_DIV               1
#else
#define BUF_UART5_RX_ITEM_SIZE              0
#define BUF_UART5_RX_RING_ITEM_NUM          0
#define BUF_UART5_RX_DMA_SIZE               0
#define BUF_UART5_TX_ITEM_SIZE              0
#define BUF_UART5_TX_RING_ITEM_NUM          0
#endif

/* VCU */
#ifdef UART6_USING
#define BUF_UART6_RX_ITEM_SIZE              264
#define BUF_UART6_RX_RING_ITEM_NUM          8
#define BUF_UART6_RX_DMA_SIZE               (2*BUF_UART6_RX_ITEM_SIZE)

#define BUF_UART6_TX_ITEM_SIZE              148
#define BUF_UART6_TX_RING_ITEM_NUM          8
#define BUF_UART6_TX_RING_DIV               1
#else
#define BUF_UART6_RX_ITEM_SIZE              0
#define BUF_UART6_RX_RING_ITEM_NUM          0
#define BUF_UART6_RX_DMA_SIZE               0
#define BUF_UART6_TX_ITEM_SIZE              0
#define BUF_UART6_TX_RING_ITEM_NUM          0
#endif

/* subg */
#define BUF_SPI1_RX_ITEM_SIZE               64
#define BUF_SPI1_RX_ITEM_NUM                4

#define BUF_SPI1_TX_ITEM_SIZE               68
#define BUF_SPI1_TX_ITEM_NUM                4
#define BUF_SPI1_TX_RING_DIV                1


/* all comm dma buff size ,  CLASS_B_END set about thiis size */
#define BUF_UART_DMA_SIZE          (BUF_UART1_RX_DMA_SIZE+BUF_UART1_TX_ITEM_SIZE +\
                                    BUF_UART2_RX_DMA_SIZE+BUF_UART2_TX_ITEM_SIZE +\
                                    BUF_UART3_RX_DMA_SIZE+BUF_UART3_TX_ITEM_SIZE +\
                                    BUF_UART4_RX_DMA_SIZE+BUF_UART4_TX_ITEM_SIZE +\
                                    BUF_UART5_RX_DMA_SIZE+BUF_UART5_TX_ITEM_SIZE +\
                                    BUF_UART6_RX_DMA_SIZE+BUF_UART6_TX_ITEM_SIZE +\
                                    BUF_SPI1_RX_ITEM_SIZE \
                                    )


#define BUF_COMM_RX_UNPACK_SIZE    ((BUF_UART1_RX_ITEM_SIZE +\
                                    BUF_UART2_RX_ITEM_SIZE +\
                                    BUF_UART3_RX_ITEM_SIZE +\
                                    BUF_UART4_RX_ITEM_SIZE +\
                                    BUF_UART5_RX_ITEM_SIZE +\
                                    BUF_UART6_RX_ITEM_SIZE +\
                                    BUF_SPI1_RX_ITEM_SIZE) *3)

/* all ring buff size,  add the item head bytes per one item */
#define BUF_COMM_RINGBUF_SIZE      (((BUF_UART1_RX_ITEM_SIZE+DMA_DATALEN_LEN)*BUF_UART1_RX_RING_ITEM_NUM+ (BUF_UART1_TX_ITEM_SIZE+DMA_DATALEN_LEN)*BUF_UART1_TX_RING_ITEM_NUM) +\
                                    ((BUF_UART2_RX_ITEM_SIZE+DMA_DATALEN_LEN)*BUF_UART2_RX_RING_ITEM_NUM+ (BUF_UART2_TX_ITEM_SIZE+DMA_DATALEN_LEN)*BUF_UART2_TX_RING_ITEM_NUM) +\
                                    ((BUF_UART3_RX_ITEM_SIZE+DMA_DATALEN_LEN)*BUF_UART3_RX_RING_ITEM_NUM+ (BUF_UART3_TX_ITEM_SIZE+DMA_DATALEN_LEN)*BUF_UART3_TX_RING_ITEM_NUM) +\
                                    ((BUF_UART4_RX_ITEM_SIZE+DMA_DATALEN_LEN)*BUF_UART4_RX_RING_ITEM_NUM+ (BUF_UART4_TX_ITEM_SIZE+DMA_DATALEN_LEN)*BUF_UART4_TX_RING_ITEM_NUM) +\
                                    ((BUF_UART5_RX_ITEM_SIZE+DMA_DATALEN_LEN)*BUF_UART5_RX_RING_ITEM_NUM+ (BUF_UART5_TX_ITEM_SIZE+DMA_DATALEN_LEN)*BUF_UART5_TX_RING_ITEM_NUM) +\
                                    ((BUF_UART6_RX_ITEM_SIZE+DMA_DATALEN_LEN)*BUF_UART6_RX_RING_ITEM_NUM+ (BUF_UART6_TX_ITEM_SIZE+DMA_DATALEN_LEN)*BUF_UART6_TX_RING_ITEM_NUM) +\
                                    ((BUF_SPI1_RX_ITEM_SIZE+DMA_DATALEN_LEN)*BUF_SPI1_RX_ITEM_NUM+ (BUF_SPI1_TX_ITEM_SIZE+DMA_DATALEN_LEN)*BUF_SPI1_TX_ITEM_NUM))


typedef struct {
    void* comm;                         /* comm handle */
    struct {
        uint32_t msgId;                 /* receive notify msg */
        
        uint8_t* buf;                   /* dma receive buff pointer*/
        uint16_t dmaBufSize;            /* dma receive buff size, double the max rx msg length */
        uint16_t head;                  /* record the new data position, for receive by dma circular mode */

        uint8_t ringItemNum;            /* receive ringbuf number */
        uint16_t ringItemSize;          /* receive ringbuf item size, must be greater than the max receive msg length */
        Ringbuf_st ringBuf;             /* receive ringbuf handle, only need one group */

        struct {                        /* for receive data unpack&parse */
            uint8_t* buf;               /* unpack buf  2*ringItemSize */
            uint16_t left;              /* last left data length in unpack buf */
        } unpack;

        uint32_t loss;                  /* rx loss num */
    } rx;

    struct {
        uint32_t msgId;                 /* transmit notify msg */
        
        uint8_t* buf;                   /* dma transmit buff pointer */
        uint16_t dmaBufSize;            /* dma receive buff size,  the max tx msg length */

        uint8_t ringItemNum;            /* tx ringbuf number */
        uint16_t ringItemSize;          /* transmit ringbuf item size, must be greater than the max tx msg length */
        uint8_t ringDiv;                /* tx ringbuf need div group, because one more task will call it */
        Ringbuf_st ringBuf[6];          /* tx ringbuf handle, max(TX_RING_DIV),  the taotal ringbuf item num of all dived ringbuf = ringItemNum */

        volatile uint8_t busy;          /* flag of recotd tx dma whether busy */
        uint64_t busyStamp;

        uint16_t cnt;                   /* the processing data item num */
        uint32_t loss;                  /* tx loss num */
    } tx;

    uint32_t err_cnt;                   /* rx err counter num */
    uint32_t last_err_code;             /* last comm error */

} commDataTypedef;

extern commDataTypedef commEntity[COMM_MAX];
COMM_TYPE_ENUM commGetCommTypeByUserId(uint8_t id);
void commInterfaceInit(void);
COMM_TYPE_ENUM commGetEntirtyTypeByDevHandler(void* dev);
int32_t commRxRingGetFreeItem(COMM_TYPE_ENUM type);
int32_t commTxRingGetFreeItem(COMM_TYPE_ENUM type);
void commMonitorRingAndLoss(void);
void commMonitorError(void);

int32_t commRxRingPush(COMM_TYPE_ENUM type, uint8_t* data, uint32_t size);
int32_t commRxRingPopAndProcess(COMM_TYPE_ENUM type, void (*comProcessFunc)(COMM_TYPE_ENUM, uint8_t*, uint32_t));

int32_t commTxRingPush(COMM_TYPE_ENUM type, uint8_t *pData, uint32_t size, uint8_t firstRing);
int32_t commTxRingPushNinebotData(COMM_TYPE_ENUM type, uint8_t *pu8Data, uint8_t u8DataSize, uint8_t u8Index, uint8_t u8Cmd, uint8_t u8SrcId, uint8_t u8DstId, uint8_t firstRing);
int32_t commTxDirectNinebotData(COMM_TYPE_ENUM type, uint8_t *pu8Data, uint8_t u8DataSize, uint8_t u8Index, uint8_t u8Cmd, uint8_t u8SrcId, uint8_t u8DstId);
int32_t commTxRingPop_SPI(COMM_TYPE_ENUM type, uint8_t* data, uint32_t len);
int32_t commTxRingPop_UART(COMM_TYPE_ENUM type);

#ifdef __cplusplus
}
#endif

#endif /* __COMMINTERFACE_H */